package com.example.dingtalkwebproject.utils;

import com.aliyun.credentials.models.Config;
import com.aliyun.dingtalkoauth2_1_0.models.CreateJsapiTicketHeaders;
import com.aliyun.dingtalkoauth2_1_0.models.CreateJsapiTicketResponse;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
import com.aliyun.dingtalkworkflow_1_0.Client;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.models.RuntimeOptions;
import com.example.dingtalkwebproject.service.CWeiXinConfigQyService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URL;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class DingTalkJsApiUtil {
    // 应用凭证
    private static final String APP_KEY = "ding5qfapkdl1d7xvj9f";
    private static final String APP_SECRET = "61ae-qWMZsgF3nISqJ6S4EfaMmC573Du0tgsoEkL8SenxQJhxXp-B2NEDajVTKbX";

    // Token缓存
    private static String cachedAccessToken;
    private static long tokenExpireTime;

    // JSAPI Ticket缓存
    private static String cachedJsApiTicket;
    private static long ticketExpireTime;




    /**
     * 初始化钉钉客户端
     */
    private static synchronized com.aliyun.dingtalkoauth2_1_0.Client getClient() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }

    /**
     * 获取AccessToken (带缓存机制)
     */
    public static String getAccessToken() {
        // 如果缓存中有未过期的Token，直接返回
        if (!StringUtils.isEmpty(cachedAccessToken) && System.currentTimeMillis() < tokenExpireTime) {
            return cachedAccessToken;
        }

        try {
            com.aliyun.dingtalkoauth2_1_0.Client client = getClient();
            GetAccessTokenRequest request = new GetAccessTokenRequest()
                    .setAppKey(APP_KEY)
                    .setAppSecret(APP_SECRET);

            GetAccessTokenResponse response = client.getAccessToken(request);

            // 更新缓存
            cachedAccessToken = response.getBody().getAccessToken();
            // 提前5分钟过期，避免临界点问题
            tokenExpireTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(response.getBody().getExpireIn()) - TimeUnit.MINUTES.toMillis(5);

            return cachedAccessToken;

        } catch (TeaException e) {
            throw new RuntimeException("获取钉钉AccessToken失败: " + e.code + " - " + e.message, e);
        } catch (Exception e) {
            throw new RuntimeException("获取钉钉AccessToken发生未知错误", e);
        }
    }

    /**
     * 获取JSAPI Ticket (带缓存机制)
     */
    public static String getJsApiTicket() throws Exception {
        // 如果缓存中有未过期的Ticket，直接返回
        if (!StringUtils.isEmpty(cachedJsApiTicket) && System.currentTimeMillis() < ticketExpireTime) {
            return cachedJsApiTicket;
        }

        try {
            String accessToken = getAccessToken();
            com.aliyun.dingtalkoauth2_1_0.Client client = getClient();

            // 使用CreateJsapiTicketHeaders方式
            CreateJsapiTicketHeaders headers = new CreateJsapiTicketHeaders();
            headers.xAcsDingtalkAccessToken = accessToken;

            // 调用createJsapiTicketWithOptions方法
            CreateJsapiTicketResponse response = client.createJsapiTicketWithOptions(headers, new RuntimeOptions());

            // 更新缓存
            cachedJsApiTicket = response.getBody().getJsapiTicket();
            // 提前5分钟过期
            ticketExpireTime = System.currentTimeMillis() +
                               TimeUnit.SECONDS.toMillis(response.getBody().getExpireIn()) -
                               TimeUnit.MINUTES.toMillis(5);

            return cachedJsApiTicket;

        } catch (TeaException e) {
            throw new RuntimeException("获取JSAPI Ticket失败: " + e.code + " - " + e.message, e);
        } catch (Exception e) {
            throw new RuntimeException("获取JSAPI Ticket发生未知错误", e);
        }
    }

    /**
     * 生成前端调用JSAPI所需的签名参数
     */
    public static JsApiSignature generateJsApiSignature(String url, String jsApiTicket) throws Exception {
        String nonceStr = getRandomStr(16);
        long timestamp = System.currentTimeMillis() / 1000;
        String signature = sign(jsApiTicket, nonceStr, timestamp, url);

        return new JsApiSignature(jsApiTicket, nonceStr, timestamp, signature);
    }

    /**
     * 计算dd.config 的签名参数
     */
    private static String sign(String jsticket, String nonceStr, long timeStamp, String url) throws Exception {
        String plain = "jsapi_ticket=" + jsticket + "&noncestr=" + nonceStr + "&timestamp=" + String.valueOf(timeStamp)
                       + "&url=" + decodeUrl(url);
        try {
            MessageDigest sha1 = MessageDigest.getInstance("SHA-256");
            sha1.reset();
            sha1.update(plain.getBytes("UTF-8"));
            return byteToHex(sha1.digest());
        } catch (Exception e) {
            throw new Exception("生成签名失败: " + e.getMessage(), e);
        }
    }

    // 字节数组转化成十六进制字符串
    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    /**
     * URL解码处理
     */
    private static String decodeUrl(String url) throws Exception {
        URL urler = new URL(url);
        StringBuilder urlBuffer = new StringBuilder();
        urlBuffer.append(urler.getProtocol());
        urlBuffer.append(":");
        if (urler.getAuthority() != null && urler.getAuthority().length() > 0) {
            urlBuffer.append("//");
            urlBuffer.append(urler.getAuthority());
        }
        if (urler.getPath() != null) {
            urlBuffer.append(urler.getPath());
        }
        if (urler.getQuery() != null) {
            urlBuffer.append('?');
            urlBuffer.append(URLDecoder.decode(urler.getQuery(), "utf-8"));
        }
        return urlBuffer.toString();
    }

    /**
     * 生成随机字符串
     */
    private static String getRandomStr(int count) {
        String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < count; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 清除所有缓存
     */
    public static void clearAllCache() {
        cachedAccessToken = null;
        tokenExpireTime = 0;
        cachedJsApiTicket = null;
        ticketExpireTime = 0;
    }

    /**
     * JSAPI签名参数对象
     */
    public static class JsApiSignature {
        private String jsapiTicket;
        private String nonceStr;
        private long timestamp;
        private String signature;

        public JsApiSignature(String jsapiTicket, String nonceStr, long timestamp, String signature) {
            this.jsapiTicket = jsapiTicket;
            this.nonceStr = nonceStr;
            this.timestamp = timestamp;
            this.signature = signature;
        }

        // Getters
        public String getJsapiTicket() {
            return jsapiTicket;
        }

        public String getNonceStr() {
            return nonceStr;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public String getSignature() {
            return signature;
        }
    }

}
